package com.gopay.common.util;

import com.jcraft.jsch.ChannelSftp;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;

/**
 * @author baiyunpeng
 * @2016年7月14日 下午3:36:05  www.gopay.com.cn Inc.All rights reserved.
 */
public class ReadFundZipUtils {
    private static Logger logger = LoggerFactory.getLogger(ReadFundZipUtils.class);
    /**
     * 读取此类格式的txt或者txt.zip文件
     * 总金额:2555.19|总笔数:3
     * 流水号|基金公司订单号|签约合同号|金额|类型|基金代码|创建时间|备注
     * <p>
     * 测的时候确保文件在sftp上是有的并且路径的正确的
     *
     * @param args
     * @throws Exception
     */
    /*public static void main(String args[]) throws Exception {
        Map<String, Object> maps = new HashMap<>();
        maps.put("ip", "211.88.2.244");
        maps.put("port", 22);
        maps.put("userName", "gopay");
        maps.put("userPwd", "tPBOv6bR");
        maps.put("timeout", 600000);
        //"supervise-redeem/rtfund/20160510"
        maps.put("path", "/home/supervise/supervise-redeem/rtfund/20160721");
        maps.put("charset", "GBK");

        String fileName = "rtfund_redeem_20160721.txt";
        maps.put("fileName", fileName);

        String saveName = "";
        String property = System.getProperty("user.dir");
        String str = property + "/rtfund/" + new SimpleDateFormat("YYYYMMdd").format(new Date());
        File file = new File(str);
        if (!file.exists()) {
            file.mkdirs();
        }
        //saveName sftp下载到的本地目录
        saveName = file + "/" + fileName.replace(".txt","");
        System.out.println(saveName);
        //saveName sftp下载到的本地目录

        //str 为本地目录包
        maps.put("str", str);
        maps.put("saveName", saveName);
        //file 为根据str目录创建的存放文件夹
        maps.put("file", file);


        Map<Integer, HashMap<String, Object>> maliao = readDifferFile(maps, ".txt");
        *//**
     * 这是返回格式
     * key    :0 value     :{签约合同号=201312160000001011, 金额=888.77, 基金代码=070008, 创建时间=2016-05-04 19:49:45.0, 类型=4, 基金公司订单号=2013121700000000111, 备注=赎回, 流水号=1}
     *//*

        String[] orders = new String[maliao.size()];
        String orderId = "";
        for (int go = 0; go < maliao.size(); go++){
            HashMap<String, Object> cat = maliao.get(go);
            orderId = (String) cat.get("备注");
            orders[go] = orderId;
        }
        for (String or : orders){
            System.out.println(or);
        }
    }*/

    /**
     * 读取zip文件
     * @param maps
     * @return
     * @throws Exception
     */
    public static List<ArrayList<String>> getFileZip(Map<String, Object> maps) throws Exception {
        ChannelSftp channel = null;
        String ip = (String) maps.get("ip");
        Integer port = (Integer) maps.get("port");
        String userName = (String) maps.get("userName");
        String userPwd = (String) maps.get("userPwd");
        Integer timeout = (Integer) maps.get("timeout");
        String path = (String) maps.get("path");
        String fileName = (String) maps.get("fileName");
        String saveName = (String) maps.get("saveName");
        File file = (File) maps.get("file");
        String charset = (String) maps.get("charset");
        String str = (String) maps.get("str");
        try {
            logger.info("连接ftp[{}]开始",ip);
            channel = SftpChannel.getChannel(ip, port, userName, userPwd, timeout);
            boolean download = SftpUtil.download(path, fileName, saveName, channel);
            if (download){
                upzip(saveName, str);
                List<ArrayList<String>> arrayLists = readTxt(charset, saveName);
                //读取完毕后将文件存放的目录删掉
                return arrayLists;
            }
            return null;
        } catch (Exception e) {
            logger.error("读取zip文件异常" , e);
            throw e;
        }finally {
            if (file != null) {
                file.delete();
            }
            if(channel!=null) {
                channel.quit();
                logger.info("连接ftp[{}]结束关闭连接",ip);
            }
            SftpChannel.closeChannel();
        }
    }

    /**
     * 读取txt文件
     * @param maps
     * @return
     * @throws Exception
     */
    public static List<ArrayList<String>> getFileTxt(Map<String, Object> maps) throws Exception {
        ChannelSftp channel = null;
        String ip = (String) maps.get("ip");
        Integer port = (Integer) maps.get("port");
        String userName = (String) maps.get("userName");
        String userPwd = (String) maps.get("userPwd");
        Integer timeout = (Integer) maps.get("timeout");
        String path = (String) maps.get("path");
        String fileName = (String) maps.get("fileName");
        String saveName = (String) maps.get("saveName");
        File file = (File) maps.get("file");
        String charset = (String) maps.get("charset");
        try {
            //连接sftp服务器
            logger.info("连接ftp[{}]开始",ip);
            channel = SftpChannel.getChannel(ip, port, userName, userPwd, timeout);
            SftpUtil.download(path, fileName, saveName, channel);
            //在本地解压缩文件成txt
            List<ArrayList<String>> arrayLists = readTxt(charset, saveName);
            //读取完毕后将文件存放的目录删掉
            return arrayLists;
        } catch (Exception e) {
            logger.error("基金读取远程文件异常",e);
            throw e;
        }finally {
            if (file != null) {
                file.delete();
            }
            if(channel!=null) {
                channel.quit();
                logger.info("连接ftp[{}]结束关闭连接",ip);
            }
            SftpChannel.closeChannel();
        }
    }

    /**
     * 解压本地文件
     * @param saveName
     * @param str
     * @throws IOException
     */
    private static void upzip(String saveName, String str) throws IOException {
        unzipToSameDir(saveName, str);
    }

    /**
     *  将编码和文件路径放入获取数据List集合
     * @param toCharset
     * @param path
     * @return
     * @throws Exception
     */
    public static List<ArrayList<String>> readTxt(String toCharset, String path) throws Exception {
        String str = path.toString();
        if (str.endsWith(".zip")) {
            int i = str.lastIndexOf(".");
            String substring = str.substring(0, i)+".txt";
            List list = getData(toCharset, substring);
            return list;
        } else {
            List list = getData(toCharset, str);
            return list;
        }
    }
    /**
     * 编码转换 : 得到结果,文件list
     *
     * @param toCharset 要转换的编码
     * @param path      要转换的文件路径
     * @return
     * @throws Exception
     */
    private static List<ArrayList> encoding(String toCharset, String path) throws Exception {
        File srcFile = new File(path);
        BufferedReader br = null;
        List list = null;
        InputStreamReader inputStreamReader = null;
        InputStream in = null;
        try {
            in = new FileInputStream(path);
            inputStreamReader = new InputStreamReader(in, toCharset);
            br = new BufferedReader(inputStreamReader);

            list = new ArrayList<>();
            StringBuilder sb = new StringBuilder();
            String s1;
            while ((s1 = br.readLine()) != null) {
                if("\r\n".equals(s1)){
                    logger.error("\r\n"+"可能有人篡改了文件的数据------------原因:文件结尾多了人为换行");
                    continue;
                }
                sb.append(s1 + "\r\n");//一行+回车
                list.add(sb.toString());
                sb.delete(0, sb.length());
            }
        } catch (Exception e) {
            LogUtil.error(logger, e,"【读取文件】失败！文件路径为：%s",path);
        } finally {
            if (br!=null){
                br.close();
            }
            if (inputStreamReader!=null){
                inputStreamReader.close();
            }
            if (in!=null){
                in.close();
            }
            srcFile.delete();//删除原来文件
        }
        return list;
    }
    /**
     * 根据文件编码和文件路径获取文件中的数据
     *
     * @param toCharset
     * @param path
     * @return
     * @throws Exception
     */
    private static List<ArrayList<String>> getData(String toCharset, String path) throws Exception {
        List list = encoding(toCharset, path);
        if(list==null){
            LogUtil.error(logger,"【读取文件】未读取到文件内容！");
            return null;
        }
        if(list.size()>0 && "\r\n".equals(list.get(list.size()-1).toString())){
            logger.error("\r\n"+"可能有人篡改了文件的数据------------原因:文件结尾多了人为换行");
        }
        List<ArrayList<String>> objectList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            List<String> list1 = new ArrayList();
            Object o = list.get(i);
            String s = o.toString();
            String regex = "[|\r\n]";
            String[] split = s.split(regex);
            for (int i1 = 0; i1 < split.length; i1++) {
                if("".equals(split[i1]) || split[i1]==null){
                    split[i1] = " ";
                }
                list1.add(i1, split[i1]);
            }
            objectList.add(i, (ArrayList) list1);
        }
        return objectList;
    }

    /**
     * 将文件解压到统一目录后删除该zip文件
     *
     * @param zipFilename
     * @param outputDirectory
     * @return
     * @throws IOException
     */
    private static List<String> unzipToSameDir(String zipFilename, String outputDirectory)
            throws IOException {
        List<String> list = new ArrayList<String>();
        File outFile = new File(outputDirectory);
        if (!outFile.exists()) {
            outFile.mkdirs();
        }
        int BUFFEREDSIZE = 1024;

        java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(zipFilename);
        Enumeration en = zipFile.entries();
        java.util.zip.ZipEntry zipEntry = null;
        while (en.hasMoreElements()) {
            zipEntry = (java.util.zip.ZipEntry) en.nextElement();
            if (!zipEntry.isDirectory()) {// unzip file
                String[] arrFolderName = StringUtils.split(zipEntry.getName(), "/");
                String outFlieName = arrFolderName[arrFolderName.length - 1];
                list.add(outFlieName);
                String strFilePath = outFile.getPath() + File.separator
                        + outFlieName;
                File f = new File(strFilePath);
                f.createNewFile();
                InputStream in = null;
                FileOutputStream out = null;
                try {
                    in = zipFile.getInputStream(zipEntry);
                    out = new FileOutputStream(f);
                    int c;
                    byte[] by = new byte[BUFFEREDSIZE];
                    while ((c = in.read(by)) != -1) {
                        out.write(by, 0, c);
                    }
                    out.flush();
                } catch (Exception e) {
                    throw e;
                } finally {
                    if (out != null) {
                        out.close();
                    }
                    if (in != null) {
                        in.close();
                    }

                    File file = new File(zipFilename);
                    file.delete();
                    zipFile.close();
                }
            }
        }
        return list;
    }
    /**
     * 读取差异文件 txt 测试用
     * @param maps
     * @return
     * @throws Exception
     */
    public static Map<Integer,HashMap<String,Object>> readDifferFile(Map maps ,String filehouzui) throws Exception {
        Map<Integer, HashMap<String,Object>> lulala = new HashMap<>();
        int count = 0;
        HashMap<String, Object> wulala = null;
        List<ArrayList<String>> fileZip = new ArrayList<>();
        if(".txt".equals(filehouzui)) {
            fileZip = getFileTxt(maps);
        } else if(".zip".equals(filehouzui)) {
            fileZip = getFileZip(maps);
        }
        String name = "";
        ArrayList arrayList = null;
        for (int i = 0; i < fileZip.size(); i++) {
            wulala = new HashMap<>();
            if (i > 1) {
                ArrayList arrayList1 = fileZip.get(1);
                arrayList = fileZip.get(i);

                for (int x = 0; x < arrayList.size(); x++) {
                    if(arrayList.get(x)!=null) {
                        wulala.put(arrayList1.get(x).toString(), arrayList.get(x));
                    }
                }

                lulala.put(count++, wulala);
            }
        }
        for (Map.Entry<Integer, HashMap<String,Object>> m : lulala.entrySet()) {
            //System.out.println("key    :" + m.getKey() + " value     :" + m.getValue());
        }
        return lulala;
    }
}
